/**
 *  Copyright (C) 2013  Piotr Szczepański
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package edu.pw.elka.gtsna.community_detection;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.pawjaw.clustering.modularity.ModularityTwoWayPartitioner;

import edu.pw.elka.gtsna.graph.Edge;
import edu.pw.elka.gtsna.graph.Graph;
import edu.pw.elka.gtsna.graph_algorithms.FindComponents;

/**
 * @author Piotr Lech Szczepański
 * @author P.Szczepanski@ii.pw.edu.pl 
 *
 */
public class MSGVMAlgorithm extends AbstractCommunityDetection{

	
	ModularityTwoWayPartitioner mtwp = new ModularityTwoWayPartitioner();
	
	/**
	 * @param graph
	 */
	public MSGVMAlgorithm(Graph graph) {
		super(graph);
		init(graph, mtwp);
	}

	public void test2() {
		mtwp.exchangeAll(); 
	}
	
	public void test3() {
		mtwp.spectralPartition();
	}
	
	
	public void test() {		
		
		mtwp.spectralPartition();
		
		List<Edge> cut = new ArrayList<Edge>();
		for (String[] edge: mtwp.findCutEdges()){
			Edge e = new Edge(Integer.valueOf(edge[0]), Integer.valueOf(edge[1]));
			cut.add(e);
		}
		System.out.println(cut);
		mtwp.dumpEdges();
		mtwp.exchangeAll();
		mtwp.reset();
		cut.clear();
		for (String[] edge: mtwp.findCutEdges()){
			Edge e = new Edge(Integer.valueOf(edge[0]), Integer.valueOf(edge[1]));
			cut.add(e);
		}
		System.out.println(cut);
	}
	
	private void init(Graph graph, ModularityTwoWayPartitioner mtwp){
		for(int node: graph.getAllNodes()){
			for (int neigbour: graph.getNeigbours(node)){
				System.out.println("Dodaje krawędź: "+node+"->"+neigbour+ " o pozycji: "+graph.pos(node)+"->"+graph.pos(neigbour));
				mtwp.addEdge( String.valueOf(graph.pos(node)), String.valueOf(graph.pos(neigbour)), 1.0f);
			}
		}
		mtwp.countEdges();
	}
	
	private void recursivePartition(Graph graph, CommunityStructure cs) throws CloneNotSupportedException{
		ModularityTwoWayPartitioner mtwp = new ModularityTwoWayPartitioner();
		System.out.println("Graph size: "+graph.getNumOfNodes());
		FindComponents c = new FindComponents(graph);
		c.compute();System.out.println(c.getComponents());
		init(graph, mtwp);
		mtwp.spectralPartition();
		mtwp.edges();
		mtwp.exchangeAll();
		System.out.println("mtwp size: "+mtwp.partition_lid.length);
		if (mtwp.modularityNoPartition() < mtwp.modularityPartitioned()) {
			Graph g1 = graph.clone();
			Graph g2 = graph.clone();
			
			for (int node: graph.getAllNodes()) {
				if (mtwp.partition_lid[graph.pos(node)] == -1) {
					g1.removeNode(node);
				} else {
					g2.removeNode(node);
				}
			}

			recursivePartition(g1, cs);
			recursivePartition(g2, cs);
		} else {
			cs.addCoalition(graph.getAllNodes());
		}
	}
	
	/* (non-Javadoc)
	 * @see edu.pw.elka.gtsna.community_detection.CommunityStructureDetectable#detectCommunities()
	 */
	@Override
	public CommunityStructure detectCommunities() {
		CommunityStructure cs = new CommunityStructure();
		try {
			recursivePartition(graph, cs);
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}

		return cs;
	}

}
